package com.ljp.chat.support.enhancement;

import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author 4everlynn
 * @version V1.0
 * @description 处理日期格式的工具类
 * @date Create at 2018/7/30
 */
public class DateWeapons {
    @SuppressWarnings("RegExpRedundantEscape")
    private static final Pattern DATE_PATTERN = Pattern.compile("^[-\\+]?[\\d]*$");

    /**
     * 提供默认日期格式化字符串的静态类
     */
    public static class DefaultType {
        public static final String FORMAT_DEFAULT = "yyyy-MM-dd HH:mm:ss";
        public static final String WITHOUT_SECONDS = "yyyy-MM-dd HH:mm";
        public static final String WITHOUT_TIME = "yyyy-MM-dd";
        public static final String CHINESE_SYMBOL_PREFIX = "yyyy年MM月dd日 HH:mm:ss";
        public static final String CHINESE_SYMBOL_SUFFIX = "yyyy-MM-dd HH时mm分ss秒";
        public static final String CHINESE_SYMBOL = "yyyy年MM月dd日 HH时mm分ss秒";
        public static final String ONLY_TODAY = "HH:mm:ss";
    }

    /**
     * UNIX时间戳 -> 日期对象
     *
     * @param timestamp 时间戳
     * @return 日期类
     */
    public static Date timestamp2Date(Long timestamp) {
        if (null == timestamp) {
            return null;
        }
        return new Date(timestamp * 1000);
    }


    public static Date timestamp2Date(Integer timestamp) {
        if (null == timestamp) {
            return null;
        }
        return timestamp2Date(timestamp.longValue());
    }

    public static String getDateFormat(String str) {
        boolean year = false;
        if (DATE_PATTERN.matcher(str.substring(0, 4)).matches()) {
            year = true;
        }
        StringBuilder sb = new StringBuilder();
        int index = 0;
        if (!year) {
            if (str.contains("月") || str.contains("-") || str.contains("/")) {
                if (Character.isDigit(str.charAt(0))) {
                    index = 1;
                }
            } else {
                index = 3;
            }
        }
        for (int i = 0; i < str.length(); i++) {
            char chr = str.charAt(i);
            if (Character.isDigit(chr)) {
                if (index == 0) {
                    sb.append("y");
                }
                if (index == 1) {
                    sb.append("M");
                }
                if (index == 2) {
                    sb.append("d");
                }
                if (index == 3) {
                    sb.append("H");
                }
                if (index == 4) {
                    sb.append("m");
                }
                if (index == 5) {
                    sb.append("s");
                }
                if (index == 6) {
                    sb.append("S");
                }
            } else {
                if (i > 0) {
                    char lastChar = str.charAt(i - 1);
                    if (Character.isDigit(lastChar)) {
                        index++;
                    }
                }
                sb.append(chr);
            }
        }
        return sb.toString();
    }

    public static Integer date2Timestamp(Date date) {
        if (null == date) {
            return null;
        }
        return Integer.valueOf(date.getTime() / 1000 + "");
    }

    /**
     * 格式化日期
     *
     * @param target 目标日期
     * @param format 目标格式
     * @return 格式化日期字符串
     */
    public static String format(Date target, String format) {
        if (null != target && StringUtils.isNoneBlank(format)) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
            return dateFormat.format(target);
        }
        return "";
    }

    public static long now() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 格式化日期
     *
     * @param timestamp UNIX时间戳
     * @param format    目标格式
     * @return 格式化日期字符串
     */
    public static String format(long timestamp, String format) {
        Date target = timestamp2Date(timestamp);
        if (StringUtils.isNoneBlank(format)) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
            return dateFormat.format(target);
        }
        return "";
    }

    public static Date from(String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(getDateFormat(format));
        try {
            return simpleDateFormat.parse(format);
        } catch (ParseException e) {
            return null;
        }
    }


    public static Date opsForLocalDateTime(Date date, Callback<LocalDateTime, LocalDateTime> callback) {
        if (null != callback) {
            LocalDateTime localDateTime;
            localDateTime = convert(date);
            localDateTime = callback.call(localDateTime);
            return localDate2Date(localDateTime);
        }
        return null;
    }

    public static Date localDate2Date(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }


    public static Date startOfYear(Date date) {
        return opsForLocalDateTime(startOfDay(date), t -> t.withDayOfMonth(1).withDayOfMonth(1));
    }

    public static Date startOfYear(Integer date) {
        if (null == date) {
            return null;
        }
        return startOfYear(date.longValue());
    }

    public static Date startOfYear(Long date) {
        if (null == date) {
            return null;
        }
        return startOfYear(timestamp2Date(date));
    }

    public static Date endOfYear(Date date) {
        if (null == date) {
            return null;
        }
        return opsForLocalDateTime(endOfDay(date), t -> t.withDayOfMonth(12).withDayOfMonth(31));
    }


    public static Date endOfYear(Long time) {
        return endOfYear(timestamp2Date(time));
    }


    /**
     * get the beginning of the day
     *
     * @param date time object
     * @return time object of day
     */
    public static Date startOfDay(Date date) {
        if (null == date) {
            return null;
        }
        return opsForLocalDateTime(date, t -> t.withHour(0).withMinute(0).withMinute(0));
    }

    public static Date startOfDay(Long time) {
        return startOfDay(timestamp2Date(time));
    }


    /**
     * get the ending of the day
     *
     * @param date time object
     * @return time object of day
     */
    public static Date endOfDay(Date date) {
        if (null == date) {
            return null;
        }
        return opsForLocalDateTime(date, t -> t.withHour(23).withMinute(59).withMinute(59));
    }

    public static Date endOfDay(Long time) {
        return endOfDay(timestamp2Date(time));
    }

    /**
     * 创建默认的格式化日期
     *
     * @param timestamp UNIX时间戳
     * @return 格式化日期字符串
     */
    public static String createDefault(long timestamp) {
        return format(timestamp, DefaultType.FORMAT_DEFAULT);
    }

    /**
     * 一次转化多个UNIX时间戳
     *
     * @param timestamp 可变参数，UNIX时间戳
     * @return 目标日期集合
     */
    public static List<Date> format(long... timestamp) {
        List<Date> result = new ArrayList<>();
        for (long current : timestamp) {
            result.add(timestamp2Date(current));
        }
        return result;
    }

    public static LocalDateTime convert(Date current) {
        Instant instant = current.toInstant();
        ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
        return zonedDateTime.toLocalDateTime();
    }

    public static LocalDateTime convert(Integer current) {
        if (null == current) {
            return convert(timestamp2Date(now()));
        }
        return convert(timestamp2Date(Long.parseLong(current.toString())));
    }


    public static int resolveQuarter(int month) {
        if (month >= 1 && month <= 3) {
            return 1;
        }
        if (month >= 4 && month <= 6) {
            return 2;
        }
        if (month >= 7 && month <= 9) {
            return 3;
        }
        if (month >= 10 && month <= 12) {
            return 4;
        }
        return -1;
    }

    public static Date translate(String dateString, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        try {
            return simpleDateFormat.parse(dateString);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return new Date();
    }

}
